import datetime
import json
import re

from re_common.baselibrary.tools.all_requests.aiohttp_request import AioHttpRequest
from re_common.baselibrary.tools.all_requests.mrequest import MRequest
from re_common.baselibrary.utils.basedict import BaseDicts
from re_common.baselibrary.utils.basetime import BaseTime

from apps.crawler_platform.core_platform.core_g import SQLTable, CoreSqlValue
from apps.crawler_platform.core_platform.g_model import DealModel, InputPlatformModel, journalInputMode, \
    RedisAllTaskModel, CallBackModel, JournalListModel, JournalIssueModel, DealInsertModel, JournalHomeModel, \
    DealUpdateModel, DealItemModel, OperatorSqlModel
from settings import get_settings

__all__ = ["para_key_callback",
           "chaoxingjournal_chaoxingjournallist_callback",
           "chaoxingjournal_chaoxingjournallist_redis_callback",
           "chaoxingjournal_chaoxingissue_callback",
           "chaoxingjournal_chaoxingarticle_callback",
            "chaoxingjournal_chaoxinghome_callback",
            "chaoxingjournal_chaoxinghomeclass_callback",
            "chaoxingjournal_chaoxingqkhomeclass_callback",
           ]


def para_key_callback(dicts):
    if isinstance(dicts, dict):
        for k, v in dicts.items():
            if not isinstance(v, (list, tuple, dict)):
                if k == "key_name":
                    v = v.replace("：", "").replace(":", "").strip()
                    v = re.sub(r"\(\d+\)", "", v)
                    dicts[k] = v
            else:
                para_key_callback(v)
    elif isinstance(dicts, (list, tuple)):
        for i in range(len(dicts)):
            para_key_callback(dicts[i])


def chaoxingjournal_chaoxingjournallist_callback(callmodel: CallBackModel[JournalListModel]) -> DealModel:
    result = DealModel()

    journal_json_dicts = {}
    dicts = {
        "主办": "publisher",
        "ISSN": "issn",
        "CN": "cnno",
        "分类": "provider_subject",
        "语言": "language",
        "周期": "type_name",
        "简介": "journal_intro",
        "总被引频次": "total_cites",
    }
    para_dicts = callmodel.para_dicts
    task_info = callmodel.redis_all.parse_dict["1_1"].task_info
    journal_rawid = callmodel.sql_model.journal_rawid
    info_dicts = {"task_name": task_info.task_name,
                  "task_tag": task_info.task_tag,
                  "journal_rawid": journal_rawid,
                  "sub_db_id": callmodel.sql_model.sub_db_id,
                  "task_tag_next": task_info.task_tag_next}
    para_dicts = para_dicts["data"]
    para_key_callback(para_dicts)

    issue_json = {}
    journal_list_json = json.loads(callmodel.sql_model.journal_json)
    issue_json["journal_name"] = journal_list_json["journal_name"]
    d_i_model = DealInsertModel()
    d_i_model.insert_pre = CoreSqlValue.replace_it
    for k, v in para_dicts.items():
        if k == "1_1":
            for k, v in para_dicts[k].items():
                if k in ["magid", "cover_url"]:
                    journal_json_dicts[k] = v
                    if k == "magid":
                        issue_json["magid"] = v
                elif k == "qk_info":
                    for item in v["children"]:
                        k = item["key_name"].strip(":").strip("：")
                        v = item["value"]
                        if k in dicts.keys():
                            k = dicts[k]
                            if k == "total_cites":
                                result.other_dicts.update({k: v})
                            else:
                                journal_json_dicts[k] = v
                        else:
                            result.other_dicts.update({k: v})
                elif k == "qk_year":
                    for item in v["children"]:
                        year = item["year"].replace("年", "")
                        issue_list = item["num"].split(",")
                        for i in issue_list:
                            temp = info_dicts.copy()
                            temp["task_tag"] = temp["task_tag_next"].split(";")[-1]
                            del temp["task_tag_next"]
                            for item_value in para_dicts["1_1"]["qk_info"]["children"]:
                                key_name = item_value["key_name"].strip(":").strip("：")
                                value = item_value["value"]
                                if key_name == "ISSN":
                                    issue_json["issn"] = value
                                elif key_name == "CN":
                                    issue_json["cnno"] = value
                                elif key_name == "分类":
                                    issue_json["provider_subject"] = value
                                elif key_name == "主办":
                                    issue_json["publisher"] = value
                            temp.update(
                                {'pub_year': year, 'num': i, 'issue_json': json.dumps(issue_json, ensure_ascii=False)})
                            # result.next_dicts["insert_ig"]["lists"].append(temp)
                            d_i_model.lists.append(temp)


                else:
                    if k in dicts.values():
                        if k == "total_cites":
                            result.other_dicts.update({k: v})
                        else:
                            journal_json_dicts[k] = v
                    else:
                        result.other_dicts.update({k: v})

            for k in dicts.keys():
                if k not in journal_json_dicts.keys():
                    result.null_dicts.update({k: ""})
    result.next_dicts.insert.append(d_i_model)
    qk_dicts = json.loads(callmodel.sql_model.journal_json)
    qk_dicts.update(journal_json_dicts)
    result.befor_dicts.update.update({"journal_json": json.dumps(qk_dicts, ensure_ascii=False)})

    return DealModel().parse_obj(result)


async def sql_select():
    sql = f'select journal_rawid from {SQLTable.journal_list} where task_name = "chaoxingjournal" and task_tag = "chaoxingjournallist" order by rand() limit 1'
    from main import app
    pool = app.state.pool
    async with pool.acquire() as conn:
        async with conn.cursor() as cur:
            await cur.execute(sql)
            row = await cur.fetchone()
    return row


async def chaoxingjournal_chaoxingjournallist_redis_callback(tmpdict: RedisAllTaskModel) -> RedisAllTaskModel:
    """
        获取model后以model传出, 更新mysql与redis 在请求cookie的API里面已经完成, 故此处不另行更新操作
        writer:zcn
    """
    redis_time_forward = tmpdict.parse_dict["1_1"].task_set.redis_uptime
    redis_time = BaseTime().str_to_timestamp(redis_time_forward)
    headers = json.loads(tmpdict.parse_dict["1_1"].task_info.headers)
    now_time = BaseTime().get_time()
    if now_time - redis_time > 3600:
        journal_rawid = await sql_select()
        data = InputPlatformModel(
            data=journalInputMode(journal_rawid=journal_rawid[0]
                                  )).json()
        url = get_settings().CHAOXING_COOKIE_GET
        rrq = AioHttpRequest()
        rrq.set_url(url) \
            .set_timeout(30).set_data(data) \
            .set_middler_list(
            [rrq.is_null_html_middlerwares, rrq.status_code_middlerwares])
        bools, dicts = await rrq.run(MRequest.POST)
        if bools:
            v_dict = json.loads(rrq.html)
            if v_dict["status"] == "SUCCESS":
                headers["Cookie"] = v_dict["data"]["Cookie"]
                tmpdict.parse_dict["1_1"].task_info.headers = headers
                tmpdict.parse_dict["1_1"].task_set.redis_uptime = str(datetime.datetime.now())
            return tmpdict
        else:
            return tmpdict
    else:
        return tmpdict



def chaoxingjournal_chaoxingissue_callback(callmodel: CallBackModel[JournalIssueModel]) -> DealModel:
    result = DealModel()
    para_dicts = callmodel.para_dicts

    task_info = callmodel.redis_all.parse_dict["1_1"].task_info
    sql_model = callmodel.sql_model
    info_dicts = {"task_name": task_info.task_name,
                  "task_tag": task_info.task_tag,
                  "task_tag_next": task_info.task_tag_next,
                  "journal_rawid": sql_model.journal_rawid,
                  "pub_year": sql_model.pub_year,
                  "num": sql_model.num,
                  "sub_db_id": sql_model.sub_db_id
                  }
    article_counts = para_dicts["data"]["1_1"]["data"][0]["datainfo"]["count"]
    # result.befor_dicts["articlecount"] = article_counts
    # result.befor_dicts["page"] = "1"
    result.befor_dicts.update.update({"articlecount": article_counts, "page": "1"})
    list_col = para_dicts["data"]["1_1"]["data"][0]["datainfo"]["data"]
    issue_json_solve = json.loads(sql_model.issue_json)
    d_i_model = DealInsertModel()
    d_i_model.insert_pre = CoreSqlValue.replace_it
    for item in list_col:
        creator = item["basic_creator"]
        date = item["basic_date"]
        dxid = item["basic_dxid"]

        issue = item["basic_source_no"]
        title = item["basic_title"]
        url = item["basic_title_url"]
        issn = item["basic_identifier_1"]
        temp = info_dicts.copy()
        temp["task_tag"] = temp["task_tag_next"]
        del temp["task_tag_next"]
        temp["creator"] = creator
        temp["date"] = date
        temp["dxid"] = dxid
        temp["issue"] = issue
        temp["title"] = title
        temp["rawid_alt"] = url.lstrip("/")
        temp["source"] = BaseDicts.is_dict_exit_key(issue_json_solve, "journal_name")
        temp["volume"] = sql_model.num.split("=")[-1]
        temp["provider_subject"] = BaseDicts.is_dict_exit_key(issue_json_solve, "provider_subject")
        temp["magid"] = BaseDicts.is_dict_exit_key(issue_json_solve, "magid")
        temp["cnno"] = BaseDicts.is_dict_exit_key(issue_json_solve, "cnno")
        if len(issn) == 0:
            temp["issn"] = BaseDicts.is_dict_exit_key(issue_json_solve, "issn")
        else:
            temp["issn"] = issn
        new_temp = {}
        new_temp["rawid"] = temp["dxid"]
        new_temp["task_tag"] = temp["task_tag"]
        new_temp["task_name"] = temp["task_name"]
        new_temp["sub_db_id"] = temp["sub_db_id"]
        del temp["dxid"]
        del temp["task_tag"]
        del temp["task_name"]
        del temp["sub_db_id"]
        del temp["num"]
        new_temp["article_info_json"] = json.dumps(temp, ensure_ascii=False)
        # result.next_dicts["replace_"]["lists"].append(new_temp)

        d_i_model.lists.append(new_temp)
    result.next_dicts.insert.append(d_i_model)

    return result


def chaoxingjournal_chaoxingarticle_callback(callmodel: CallBackModel[JournalIssueModel]) -> DealModel:
    result = DealModel()
    return result


def chaoxingjournal_chaoxinghome_callback(callmodel: CallBackModel[JournalHomeModel]) -> DealModel:
    result = DealModel()
    para_dicts = callmodel.para_dicts
    data = para_dicts["data"]
    task_info = callmodel.redis_all.parse_dict["1_1"].task_info
    info_dicts = {"task_name": callmodel.sql_model.task_name,
                  "task_tag": callmodel.sql_model.task_tag,
                  "sub_db_id": callmodel.sql_model.sub_db_id,
                  "task_tag_next": task_info.task_tag_next}
    if "1_1" in data:
        d_i_model = DealInsertModel()
        d_i_model.insert_pre = CoreSqlValue.insert_ig_it
        for item in data["1_1"]['onelevel']:
            if item["fenleiname"] == "推荐":
                continue
            temp = info_dicts.copy()
            temp["task_tag"] = temp["task_tag_next"]
            del temp["task_tag_next"]
            field = item["fenleiname"]
            temp["home_rawid"] = item["fenleiid"]
            json_temp = {
                "field": field,
            }
            temp["home_json"] = json.dumps(json_temp, ensure_ascii=False)
            d_i_model.lists.append(temp)
        result.befor_dicts.insert.append(d_i_model)
    return result


def chaoxingjournal_chaoxinghomeclass_callback(callmodel: CallBackModel[JournalHomeModel]) -> DealModel:
    result = DealModel()
    para_dicts = callmodel.para_dicts
    data = para_dicts["data"]
    task_info = callmodel.redis_all.parse_dict["1_1"].task_info
    info_dicts = {"task_name": callmodel.sql_model.task_name,
                  "task_tag": callmodel.sql_model.task_tag,
                  "sub_db_id": callmodel.sql_model.sub_db_id,
                  "task_tag_next": task_info.task_tag_next}
    if "1_1" in data:
        d_i_model = DealInsertModel()
        d_i_model.insert_pre = CoreSqlValue.insert_ig_it
        for item in data["1_1"]['other']:
            temp = info_dicts.copy()
            temp["task_tag"] = temp["task_tag_next"]
            del temp["task_tag_next"]
            field = item["fenleiname"]
            temp["home_rawid"] = item["fenleiid"]
            befor_field = json.loads(callmodel.sql_model.home_json)["field"]
            json_temp = {
                "his": befor_field + "->" + field,
                "field": field,
            }
            temp["home_json"] = json.dumps(json_temp, ensure_ascii=False)
            d_i_model.lists.append(temp)
        result.befor_dicts.insert.append(d_i_model)
    return result


def chaoxingjournal_chaoxingqkhomeclass_callback(callmodel: CallBackModel[JournalHomeModel]) -> DealModel:
    result = DealModel()
    para_dicts = callmodel.para_dicts
    task_info = callmodel.redis_all.parse_dict["1_1"].task_info
    info_dicts = {"task_name": callmodel.sql_model.task_name,
                  "task_tag": callmodel.sql_model.task_tag,
                  "sub_db_id": callmodel.sql_model.sub_db_id,
                  "task_tag_next": task_info.task_tag_next}
    if "1_1" in para_dicts["data"]:
        data = para_dicts["data"]["1_1"]
        total_page = int(data['max_page_info'].split('/')[-1])
        result.code_dicts = {
            "1_1": {"max_page": total_page}
        }
        page_index = int(callmodel.sql_model.page_index)
        turn_page = task_info.turn_page
        if (turn_page == 7 and page_index < 3) or (turn_page == 8 and page_index < 4):
            sql_dict = callmodel.sql_model.dict()
            tmp_list = [
                {
                    "key": "task_name",
                    "value": sql_dict["task_name"],
                    "operator": "=",
                    "description": "and"
                },
                {
                    "key": "task_tag",
                    "value": sql_dict["task_tag"],
                    "operator": "=",
                    "description": "and"
                },
                {
                    "key": "home_rawid",
                    "value": sql_dict["home_rawid"],
                    "operator": "=",
                    "description": "and"
                },
                {
                    "key": "page_index",
                    "value": total_page,
                    "operator": ">",
                    "description": "and"
                }
            ]
            du_model_bef_1 = DealUpdateModel()
            du_model_bef_1.update.update({"is_active": "0"})
            list_op = []
            for item in tmp_list:
                op = OperatorSqlModel()
                list_op.append(op.parse_obj(item))
            du_model_bef_1.where = list_op
            result.befor_dicts.update_list.append(du_model_bef_1)
            tmp_list[-1]["operator"] = "<="
            du_model_bef_2 = DealUpdateModel()
            du_model_bef_2.update.update({"is_active": "1"})
            list_op1 = []
            for item in tmp_list:
                op = OperatorSqlModel()
                list_op1.append(op.parse_obj(item))
            du_model_bef_2.where = list_op1
            result.befor_dicts.update_list.append(du_model_bef_2)

            di_model_bef = DealInsertModel()
            di_model_bef.insert_pre = CoreSqlValue.insert_ig_it
            sql_dict.pop("id")
            sql_dict.pop("update_time")
            sql_dict.pop("create_time")
            sql_dict.pop("null_dicts")
            sql_dict.pop("err_msg")
            sql_dict.pop("other_dicts")
            sql_dict.pop("state")
            sql_dict.pop("failcount")
            for page in range(page_index, total_page + 1):
                sql_dict["page_index"] = page
                di_model_bef.lists.append(sql_dict.copy())
            result.befor_dicts.insert.append(di_model_bef)
        di_model_next = DealInsertModel()
        di_model_next.insert_pre = CoreSqlValue.insert_ig_it
        home_json = json.loads(callmodel.sql_model.home_json)
        his = home_json["his"]
        for item in data['qk_info']['children']:
            result.befor_dicts.update.update({'page': total_page})
            journal_rawid = item['url'].split('mags=')[-1]
            qk_name = item['name']
            publisher = item['organ']
            impact = item['impact']
            read_cnt = item['read']
            cited_cnt = item['cited']

            new_dict = dict()
            new_dict["publisher"] = publisher
            new_dict["impact"] = impact
            new_dict["journal_name"] = qk_name
            new_dict["read_cnt"] = read_cnt
            new_dict["cited_cnt"] = cited_cnt

            temp_info = info_dicts.copy()
            task_tag_next = temp_info["task_tag_next"]
            temp_info["task_tag"] = task_tag_next
            del temp_info["task_tag_next"]
            temp_info["journal_rawid"] = journal_rawid
            temp_info["sub_db_id"] = "00006"
            temp_info["is_active"] = "1"
            temp_info["journal_json"] = json.dumps(new_dict, ensure_ascii=False)
            di_model_next.lists.append(temp_info)

            du_model = DealUpdateModel()
            # du_model.update_no_placeholder.update({"page": max_page})
            du_model.update.update({"journal_json": json.dumps(new_dict, ensure_ascii=False),
                                    "sub_db_id": "00006",
                                    "is_active": "1"})
            du_model.where.update({"journal_rawid": journal_rawid,
                                   "task_tag": temp_info["task_tag"],
                                   "task_name": callmodel.sql_model.task_name,
                                   "is_active": "0"})
            du_model.update_no_placeholder.update({"subject": f'CONCAT(`subject`,";{his}")'})
            result.next_dicts.update_list.append(du_model)

        result.next_dicts.insert.append(di_model_next)

    return result